package com.ruoyi.rsikManage.controller;

import java.io.IOException;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.rsikManage.domain.*;
import com.ruoyi.rsikManage.domain.common.StatisticsRequest;
import com.ruoyi.rsikManage.domain.vo.*;
import com.ruoyi.rsikManage.service.ITAlarmsService;
import com.ruoyi.rsikManage.service.JyService;
import com.ruoyi.rsikManage.service.MonitorPointService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

/**
 * 报警信息Controller
 *
 * @author ljw
 * @date 2023-08-08
 */
@RestController
@RequestMapping("/zdzh/alarms")
@SuppressWarnings("all")
public class TAlarmsController extends BaseController
{
    @Autowired
    JyService jyService;
    @Autowired
    MonitorPointService monitorPointService;
    @Autowired
    private ITAlarmsService tAlarmsService;
    @Autowired
    ServletContext servletContext;

    @Autowired
    private TokenService tokenService;

    @Value("${jy.ip}")
    private String JY_IP;
    @Value("${UNDERGROUND_ELECTRICITY_SYSTEM_IP}")
    private String UNDERGROUND_ELECTRICITY_SYSTEM_IP;
    @Value("${personnel_positioning_platform_ip}")
    private String PERSONNEL_POSITIONING_PLATFORM_IP;
    /**
     * 联网状态
     */
    @GetMapping ("networkConnectStatus")
    public AjaxResult selectNetworkConnectStatus() {

        CompletableFuture<Boolean> jyConnectFuture = CompletableFuture.supplyAsync(() -> isReachable(JY_IP));
        CompletableFuture<Boolean> undergroundElectricityFuture = CompletableFuture.supplyAsync(() -> isReachable(UNDERGROUND_ELECTRICITY_SYSTEM_IP));
        CompletableFuture<Boolean> undergroundPersonnelFuture = CompletableFuture.supplyAsync(() -> isReachable(PERSONNEL_POSITIONING_PLATFORM_IP));

        List<NetworkConnectStatusVo> res = new ArrayList<>(3);

        boolean jyConnectStatus = jyConnectFuture.join();
        res.add(new NetworkConnectStatusVo(1, "极云平台", jyConnectStatus));

        boolean undergroundPersonnelPositioning = undergroundPersonnelFuture.join();
        res.add(new NetworkConnectStatusVo(2, "井下人员", undergroundPersonnelPositioning));

        boolean undergroundElectricityConnectStatus = undergroundElectricityFuture.join();
        res.add(new NetworkConnectStatusVo(3, "井下电力", undergroundElectricityConnectStatus));



        return AjaxResult.success(res);
    }

    /**
     * 查询并转化监控点离线超时报警的配置时间
     */
    @GetMapping("times-of-monitor-offline-alarm")
    public AjaxResult selectTimesOfMonitorOfflineAlarm() {
        HashMap<String, Object> res = new HashMap<>();
        MonitorsOfflineAlarmSettings monitorOfflineAlarmSettings = monitorPointService.selectMonitorOfflineAlarmSettings();
        Integer setMinutes = monitorOfflineAlarmSettings.getSetMinutes();
        res.put("hours", setMinutes / 60);
        res.put("minutes", setMinutes % 60);
        res.put("isOfflineTimeoutAlarmEnabled", monitorOfflineAlarmSettings.isOfflineTimeoutAlarmEnabled);
        return success(res);
    }
    /**
     * 修改监控点离线超时报警的配置时间
     */
    @PutMapping("times-of-monitor-offline-alarm")
    public AjaxResult updateTimesOfMonitorOfflineAlarm(@RequestBody HashMap<String, Object> map) {
        Integer hours = (Integer) map.get("hours");
        Integer minutes = (Integer) map.get("minutes");
        boolean isOfflineTimeoutAlarmEnabled = (boolean) map.getOrDefault("isOfflineTimeoutAlarmEnabled",false);

        if (hours == null || minutes == null) {
            return error("请正确输入时间，需要包含小时数和分钟数");
        }

        Integer setMinutes = hours * 60 + minutes;
        MonitorsOfflineAlarmSettings monitorOfflineAlarmSettings = new MonitorsOfflineAlarmSettings(setMinutes, isOfflineTimeoutAlarmEnabled);
        monitorPointService.updateMonitorOfflineAlarmSettings(monitorOfflineAlarmSettings);
        return success();
    }

    /**
     * 接收算法报警的信息 （仅用于测试）
     * @param alarmEvent
     * @return
     */
    @PostMapping("algo-alarm")
    public AjaxResult receiveAlgoAlarm(@RequestBody List<HashMap> list) {
        System.out.println("接收到算法报警信息：" + list.toString());
        return success();
    }

    /**
     * 接收监控点掉线报警的信息 （仅用于测试）
     * @param alarmEvent
     * @return
     */
    @PostMapping("monitor-offline-alarm")
    public AjaxResult receiveMonitorOfflineAlarm(@RequestBody MonitorPoint monitor) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("监控点掉线报警:" + dateFormat.format(monitor.getUpdateDate()) + " "+ monitor.getName() + "掉线了");
        return success("监控点掉线报警信息发送成功");
    }
    /**
     * 接收视频质量诊断结果异常的报警信息 （仅用于测试）
     * @param alarmEvent
     * @return
     */
    @PostMapping("diagnosis-abnormal-alarm")
    public AjaxResult receiveDiagnosisAbnormalAlarm(@RequestBody VideoDiagnosisResult videoDiagnosisResult) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("视频质量诊断结果异常报警:" + dateFormat.format(videoDiagnosisResult.getDiagnosisTime()) + " "+videoDiagnosisResult.getChannelName() + "视频质量异常了");
        return success("视频质量诊断结果异常报警信息发送成功");
    }
    /**
     * 0.统计一段时间内，各场所AI报警次数
     */
    @GetMapping("count-place-category-list")
    public AjaxResult countPlaceCategoryList(Date startTime, Date endTime) {
        String provinceFileDicVal = "0";
        List<PlaceCategory> placeCategoryList = tAlarmsService.countPlaceCategoryList(provinceFileDicVal, startTime, endTime);
        if (StringUtils.isNull(placeCategoryList))
        {
            placeCategoryList = new ArrayList<PlaceCategory>();
        }
        return success(placeCategoryList);
    }

    /**
     * 统计一段时间内，各场所类别下各场所的AI报警数，以及各场所类别下各场所的AI报警数
     */
    @GetMapping("count-alarm-of-category-and-place/v2")
    public AjaxResult countAlarmOfCategoryAndPlace(Date startTime, Date endTime) {
        List<PlaceCategory> res =  tAlarmsService.countAlarmOfCategoryAndPlace(startTime, endTime);

        if (StringUtils.isNull(res))
        {
            res = new ArrayList<PlaceCategory>();
        }

        return success(res);
    }

    /**
     * 统计一段时间内，各场所类别下各场所的AI报警数，以及各场所类别下各场所的AI报警数
     * 修改时间 24/10/24
     * 修改原因 新增权限管理
     */
    @PostMapping("count-alarm-of-category-and-place")
    public AjaxResult countAlarmOfCategoryAndPlaceForUnitCodes(@RequestBody StatisticsRequest statisticsRequest,
                                                               HttpServletRequest httpServletRequest) {
        List<PlaceCategory> res= new ArrayList<>();
        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();
        // 如果 unitCodes 为空或为空列表，则从登录用户信息中获取
        if (unitCodes == null || unitCodes.isEmpty()) {
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        res =  tAlarmsService.countAlarmOfCategoryAndPlaceForUnitCodes(startTime,endTime,unitCodes);


        return success(res);
    }

    /**
     * 统计各场所类别的已部署算法个数
     */
    @GetMapping("count-algo-of-category")
    public AjaxResult countAlgoOfCategory() {
        List<PlaceCategory> res = tAlarmsService.countAlgoOfCategory();
        return success(res);
    }
    /**
     * 统计一段时间内，每天的报警数（当天的报警数 = 未处置报警 + 正报 + 误报）
     */
    @GetMapping("count-alarm-of-each-day/v2")
    public AjaxResult countAlarmOfEachDay(Date startTime, Date endTime, String alarmName) {
        List<AlarmOfEachDayVo> res = tAlarmsService.countAlarmOfEachDay(startTime, endTime, alarmName);
        return success(res);
    }

    /**
     * 统计一段时间内，每天的报警数（当天的报警数 = 未处置报警 + 正报 + 误报）
     * 该方法用于统计在指定时间范围内的报警次数。
     * 创建时间: 2024-10-21
     * 更新原因：权限功能新增v1
     * @param startTime 开始时间，用于限定统计的时间范围的起始点。
     * @param endTime 结束时间，用于限定统计的时间范围的结束点。
     * @param unitCodes 筛选的煤矿编码数组。
     * @return 返回一个包含报警次数的映射，其中键为 "num"，值为报警次数。
     */
//    @PostMapping("count-alarm-of-each-day")
    @RequestMapping(value = "count-alarm-of-each-day", method = {RequestMethod.GET, RequestMethod.POST})
    public AjaxResult countAlarmOfEachDayV2(@RequestBody(required = false) StatisticsRequest statisticsRequest,
                                            HttpServletRequest httpServletRequest) {
        LocalDateTime startTime;
        LocalDateTime endTime;
        LocalDateTime now = LocalDateTime.now();
        String alarmName;
        if (statisticsRequest != null) {
            startTime = statisticsRequest.getStartTime();
            endTime = statisticsRequest.getEndTime();
            alarmName = statisticsRequest.getAlarmName();

        } else {
            startTime = null;
            endTime = null;
            alarmName = null;
        }
        startTime = startTime != null ? startTime : now.toLocalDate().atStartOfDay();
        endTime = endTime != null ? endTime : now.toLocalDate().atTime(23, 59, 59);
        // 初始化单位代码列表
        List<Long> unitCodes = new ArrayList<>();

        // 如果请求体不为空，则从请求体中获取单位代码
        if (statisticsRequest != null) {
            unitCodes = statisticsRequest.getUnitCodes();
        }
        // 如果单位代码列表为空，则尝试从当前登录用户获取单位代码
        if (unitCodes == null || unitCodes.isEmpty()) {
            if (httpServletRequest != null && tokenService.getTokenInfo(httpServletRequest) != null) {
                unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
            }
        }

        List<AlarmOfEachDayVo> res = tAlarmsService.countAlarmOfEachDayForUnitCodes(startTime, endTime, alarmName,unitCodes);
        return success(res);
    }


    /**
     * 统计一段时间内的：报警总数、一级报警数、二级报警数、三级报警数
     */
    @GetMapping("count-alarm-of-each-level")
    public AjaxResult countAlarmOfEachLevel(@RequestParam("startTime") Date startTime, @RequestParam("endTime") Date endTime) {
        List<AlarmOfEachLevelVo> res = tAlarmsService.countAlarmOfEachLevel(startTime, endTime);
        return success(res);
    }

    /**
     * 3.统计各监控点在一段时间内的掉线次数 √
     */
    @GetMapping("count-offline-for-each-monitor/v2")
    public AjaxResult countOfflineForEachMonitor(Date startTime, Date endTime) {
        List<HistogramVo> res = tAlarmsService.countOfflineForEachMonitor(startTime, endTime);
        return success(res);
    }

    /**
     * 3.统计各监控点在一段时间内的掉线次数 √
     */
    @PostMapping("count-offline-for-each-monitor")
    public AjaxResult countOfflineForEachMonitorForUnitCodes(@RequestBody StatisticsRequest statisticsRequest,
                                                             HttpServletRequest httpServletRequest) {

        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();
        if (unitCodes ==null || unitCodes.isEmpty()){
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        List<HistogramVo> res = tAlarmsService.countOfflineForEachMonitorForUnitCodes(startTime, endTime,unitCodes);
        return success(res);
    }

    /**
     * 4.统计监控点掉线次数在时间维度（月）的变化曲线 (近12个月) √
     */
    @GetMapping("count-offline-for-each-month/v2")
    public AjaxResult countOfflineForEachMonth() {
        List<HistogramVo> res = tAlarmsService.countOfflineForEachMonth();
        return success(res);
    }

    /**
     * 4.统计监控点掉线次数在时间维度（月）的变化曲线 (近12个月) √
     * 变更时间 24/10/25
     * 变更原因 新增权限管理 新增unitCodes筛选
     */
    @PostMapping("count-offline-for-each-month")
    public AjaxResult countOfflineForEachMonthForUnitCodes(@RequestBody StatisticsRequest statisticsRequest,
                                                           HttpServletRequest httpServletRequest) {
        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();

        if (unitCodes ==null || unitCodes.isEmpty()){
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        List<HistogramVo> res = tAlarmsService.countOfflineForEachMonthForUnitCodes(startTime,endTime,unitCodes);
        return success(res);
    }

    /**
     * 5.统计各监控点在一段时间内的诊断不合格报警次数 √
     */
    @GetMapping("count-diagnosis-abnormal/v2")
    public AjaxResult countDiagnosisAbnorForEachMonitor(Date startTime, Date endTime) {
        List<HistogramVo> res = tAlarmsService.countDiagnosisAbnorForEachMonitor(startTime, endTime);
        return success(res);
    }

    /**
     * 5.统计各监控点在一段时间内的诊断不合格报警次数 √
     * 修改时间 24/10/25
     * 修改原因 新增权限管理筛选 GET -> POST
     */
    @PostMapping("count-diagnosis-abnormal")
    public AjaxResult countDiagnosisAbnorForEachMonitorForUnitCodes(@RequestBody StatisticsRequest statisticsRequest,
                                                                    HttpServletRequest httpServletRequest) {
        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();
        if (unitCodes == null || unitCodes.isEmpty()){
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        List<HistogramVo> res = tAlarmsService.countDiagnosisAbnorForEachMonitorForUnitCodes(startTime, endTime,unitCodes);
        return success(res);
    }



    /**
     * 6.统计诊断异常次数在时间维度（月）的变化曲线 √
     */
    @GetMapping("count-diagnosis-abnor-for-each-monitor/v2")
    public AjaxResult countDiagnosisAbnorForEachMonth(Date startTime, Date endTime) {
        List<HistogramVo> res = tAlarmsService.countDiagnosisAlarmForEachMonth(startTime, endTime);
        return success(res);
    }

    /**
     * 6.统计诊断异常次数在时间维度（月）的变化曲线 √
     */
    @PostMapping("count-diagnosis-abnor-for-each-monitor")
    public AjaxResult countDiagnosisAbnorForEachMonthForUnitCodes(@RequestBody StatisticsRequest statisticsRequest,
                                                                  HttpServletRequest httpServletRequest) {
        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();
        if (unitCodes == null || unitCodes.isEmpty()) {
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        List<HistogramVo> res = tAlarmsService.countDiagnosisAlarmForEachMonthForUnitCodes(startTime, endTime,unitCodes);
        return success(res);
    }
    /**
     * 7. 统计一段时间内，各AI报警类型的个数 √
     */
    @GetMapping("count-ai-alarm-for-each-type")
    public AjaxResult countAlgoAlarmForEachType(Date startTime, Date endTime) {
        List<HistogramVo> res = tAlarmsService.countAlgoAlarmForEachType(startTime, endTime);
        return success(res);
    }
    /**
     * 8. 统计AI报警数在时间维度(月)的变化曲线 √
     */
    @GetMapping("count-ai-alarm-for-each-month/v2")
    public AjaxResult countAlgoAlarmForEachMonth(String alarmName) {
        List<HistogramVo> res = tAlarmsService.countAlgoAlarmForEachMonth(alarmName);
        return success(res);
    }

    /**
     * 8. 统计AI报警数在时间维度(月)的变化曲线 √
     *    修改时间 24/10/25
     *    修改原因 新增权限管理
     */
    @PostMapping("count-ai-alarm-for-each-month")
    public AjaxResult countAlgoAlarmForEachMonth(@RequestBody StatisticsRequest statisticsRequest,
                                                 HttpServletRequest httpServletRequest) {
        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        List<Long> unitCodes = statisticsRequest.getUnitCodes();
        String alarmName = statisticsRequest.getAlarmName();
        if (unitCodes == null || unitCodes.isEmpty()) {
            unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
        }
        List<HistogramVo> res = tAlarmsService.countAlgoAlarmForEachMonthForUnitCodes(startTime,endTime,alarmName,unitCodes);
        return success(res);
    }

    /**
     * 9. 统计不同报警等级的报警个数
     */
    @GetMapping("count-alarm-level")
    public AjaxResult countAlarmLevel() {
        List<HistogramVo> res = tAlarmsService.countAlarmLevel();
        return success(res);
    }


    /**
     * 10. 统计某段时间范围内报警类型排行
     */
    @GetMapping("count-alarm-type/v2")
    public AjaxResult countAlarmType(Date startTime, Date endTime) {
        List<Map<String,Object>> res = tAlarmsService.countAlarmType(startTime,endTime);
        return success(res);
    }


    /**
     * 10. 统计某段时间范围内报警类型排行
     * 创建时间: 2024-10-21
     * 更新原因：权限功能新增v1
     * @param startTime 开始时间，用于限定统计的时间范围的起始点。
     * @param endTime 结束时间，用于限定统计的时间范围的结束点。
     * @param unitCodes 筛选的煤矿编码数组。
     * @return 返回一个包含报警次数的映射，其中键为 "num"，值为报警次数。
     */
    @PostMapping("count-alarm-type")
    public AjaxResult countAlarmTypeForUnitCodes(@RequestBody(required = false) StatisticsRequest statisticsRequest,
                                                 HttpServletRequest httpServletRequest) {


        LocalDateTime startTime = statisticsRequest.getStartTime();
        LocalDateTime endTime = statisticsRequest.getEndTime();
        LocalDateTime now = LocalDateTime.now();

        // 如果 startTime 未被设置，则默认为当天的开始时间 (00:00:00)
        if (startTime == null) {
            startTime = now.toLocalDate().atStartOfDay();
        }

        // 如果 endTime 未被设置，则默认为当天的结束时间 (23:59:59.999999999)
        if (endTime == null) {
            endTime = now.toLocalDate().atTime(23, 59, 59, 999_999_999);
        }
        // 初始化单位代码列表
        List<Long> unitCodes = new ArrayList<>();

        // 如果请求体不为空，则从请求体中获取单位代码
        if (statisticsRequest != null) {
            unitCodes = statisticsRequest.getUnitCodes();
        }
        // 如果单位代码列表为空，则尝试从当前登录用户获取单位代码
        if (unitCodes == null || unitCodes.isEmpty()) {
            if (httpServletRequest != null && tokenService.getTokenInfo(httpServletRequest) != null) {
                unitCodes = tokenService.getLoginUserUnitCodes(httpServletRequest);
            }
        }


        List<Map<String,Object>> res = tAlarmsService.countAlarmTypeForUnitCodes(startTime,endTime,unitCodes);
        if (res.size()==0){
            HashMap<String, Object> map = new HashMap<>();
            map.put("alarmTypeName","暂无告警");
            map.put("AlarmTypeCount",0);
            res.add(map);
        }
        return success(res);
    }

    private boolean isReachable(String ip) {
        try {
            InetAddress address = InetAddress.getByName(ip);
            return address.isReachable(1000);
        } catch (IOException e) {
            return false;
        }
    }
}
